﻿using Dyao.Book.Contract;
using Dyao.Book.Entity;

namespace Dyao.Book.Application.TaskCenter
{
    public class TaskCenterUpdatingContext : PropertyChangeStore
    {
        public const string EXCUTERESULT_PROPERTY_NAME = nameof(TaskCenterRecordExtensionEntity.ExcuteResult);
        public const string EXCUTINGINFO_PROPERTY_NAME = nameof(TaskCenterRecordExtensionEntity.ExcutingInfo);

        private readonly TaskCenterRecordEntity _entity;
        private DirtyCollection _extensionDirtys;

        private ExtensionInfoLocal _extension;
        private Func<ExtensionInfoLocal, string[], Task> _extensionFactory;

        public TaskCenterUpdatingContext(TaskCenterRecordEntity entity,
            ExtensionInfoLocal extension = null,
            Func<ExtensionInfoLocal, string[], Task> extensionFacotry = null)
            : base(entity)
        {
            if (extensionFacotry == null
                && (extension == null
                || !(extension.ExcutingInfoIsLoaded && extension.ResultIsLoaded)))
            {
                throw new ArgumentException("未设置任务扩展信息或获取来源方式");
            }
            _entity = entity;
            _extension = extension;
            _extensionFactory = extensionFacotry;
        }

        protected DirtyCollection ExtensionDirtys => _extensionDirtys ??= new DirtyCollection();

        protected ExtensionInfoLocal Extension => _extension ??= new ExtensionInfoLocal();
        internal TaskCenterRecordEntity Record => _entity;

        /// <summary>
        /// 执行进度
        /// </summary>
        public decimal ExcutingProgress
        {
            get { return _entity.ExcutingProgress; }
            set { SetValueIfNoEqual(nameof(_entity.ExcutingProgress), value); }
        }

        /// <summary>
        /// 运行开始时间
        /// </summary>
        public DateTime? ExcuteBeginDatetime
        {
            get { return _entity.ExcuteBeginDatetime; }
            set { SetValueIfNoEqual(nameof(_entity.ExcuteBeginDatetime), value); }
        }

        /// <summary>
        /// 运行结束时间
        /// </summary>
        public DateTime? ExcuteEndDatetime
        {
            get { return _entity.ExcuteEndDatetime; }
            set { SetValueIfNoEqual(nameof(_entity.ExcuteEndDatetime), value); }
        }

        /// <summary>
        /// 超时秒数
        /// </summary>
        public int? TimeOutSecond
        {
            get { return _entity.TimeOutSecond; }
        }

        /// <summary>
        /// 是否超时
        /// </summary>
        public bool IsTimeOut
        {
            get { return _entity.IsTimeOut; }
            set { SetValueIfNoEqual(nameof(_entity.IsTimeOut), value); }
        }

        /// <summary>
        /// 重试次数
        /// </summary>
        public int RetryCount
        {
            get { return _entity.RetryCount; }
        }

        /// <summary>
        /// 状态
        /// </summary>
        public TaskCenterRecordStatusEnum Status
        {
            get { return _entity.Status; }
            set { SetValueIfNoEqual(nameof(_entity.Status), value); }
        }

        /// <summary>
        /// 运行结果信息
        /// </summary>
        public string ResultMessage
        {
            get { return _entity.ResultMessage; }
            set { SetValueIfNoEqual(nameof(_entity.ResultMessage), value); }
        }

        public DateTime? RowVersion
        {
            get { return _entity.RowVersion; }
        }

        public void SetRowVersion(DateTime dateTime)
        {
            _entity.RowVersion = (DateTime?)dateTime;
        }

        #region extensions

        /// <summary>
        /// 获取运行中信息
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetExecutingInfoAsync()
        {
            if (!Extension.ExcutingInfoIsLoaded)
            {
                await LoadExtensionAsync(EXCUTINGINFO_PROPERTY_NAME);
            }
            
            return Extension.ExcutingInfo;
        }

        /// <summary>
        /// 获取执行结果
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetExecutedResultAsync()
        {
            if (!Extension.ResultIsLoaded)
            {
                await LoadExtensionAsync(EXCUTERESULT_PROPERTY_NAME);
            }

            return Extension.ExcuteResult;
        }

        public async Task<(string, string)> GetExecutingInfoAndResultAsync()
        {
            if (!Extension.ResultIsLoaded || !Extension.ExcutingInfoIsLoaded)
            { 
                await LoadExtensionAsync(EXCUTINGINFO_PROPERTY_NAME, EXCUTERESULT_PROPERTY_NAME);
            }

            return (Extension.ExcutingInfo, Extension.ExcuteResult);
        }

        /// <summary>
        /// 设置执行结果
        /// </summary>
        /// <param name="result"></param>
        public void SetExecutedResult(string result)
        {
            var propertyName = EXCUTERESULT_PROPERTY_NAME;
            var isLoaded = Extension.ResultIsLoaded;

            if (!isLoaded || (isLoaded && !CheckEqual(Extension.ExcuteResult, result)))
            {
                ExtensionDirtys[propertyName] = true;
                Extension.ExcuteResult = result;
            }
        }

        /// <summary>
        /// 设置运行中信息
        /// </summary>
        /// <param name="executingInfo"></param>
        public void SetExecutingInfo(string executingInfo)
        {
            var propertyName = EXCUTINGINFO_PROPERTY_NAME;
            var isLoaded = Extension.ExcutingInfoIsLoaded;

            if (!isLoaded || (isLoaded && !CheckEqual(Extension.ExcutingInfo, executingInfo)))
            {
                ExtensionDirtys[propertyName] = true;
                Extension.ExcutingInfo = executingInfo;
            }
        }

        public bool ExtensionHasChanges()
        {
            return _extensionDirtys != null && ExtensionDirtys.Any();
        }

        public IReadOnlyList<string> GetExtensionChangeProperties()
        {
            return _extensionDirtys?.GetAll();
        }

        private async Task LoadExtensionAsync(params string[] propertyNames)
        {
            if (propertyNames.Length == 0) return;

            await _extensionFactory(Extension, propertyNames);
        }

        #endregion //end extensions
    }
}
